﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Asol.Reporting.Support.XmlPersistor.Internal;

namespace Asol.Reporting.Support.XmlPersistor
{
    #region class Persist : Třída, která zajišťuje persistenci dat do / z XML formátu
    /// <summary>
    /// Třída, která zajišťuje persistenci dat do / z XML formátu
    /// </summary>
    public static class XmlPersist
    {
        #region Statické public metody pro serializaci a deserializaci objektu
        /// <summary>
        /// Zajistí persistenci (uložení = serializaci) datového objektu do stringu podle implicitních parametrů.
		/// Vrátí stringovou reprezentaci objektu.
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string Serialize(object data)
        {
            return Serialize(data, XmlPersistArgs.Default);
        }
        /// <summary>
        /// Zajistí persistenci (uložení = serializaci) datového objektu do stringu podle daných parametrů.
		/// Pokud je v parametru vyplněn soubor (XmlFile), pak je XML uložen do daného souboru, v korektním kódování UTF-8 (včetně záhlaví XML!)
		/// Vrátí stringovou reprezentaci objektu.
		/// </summary>
        /// <param name="data"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static string Serialize(object data, XmlPersistArgs parameters)
        {
            return XmlPersistor.Internal.XmlPersistor.Serialize(data, parameters);
        }
        /// <summary>
        /// Vytvoří objekt ze serializovaného stavu, který je dodán jako string do této metody.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static object Deserialize(string source)
        {
            return Deserialize(CreateArgs(source));
        }
        /// <summary>
		/// Vytvoří objekt ze serializovaného stavu, který je definován v argumentu (může to být string, nebo soubor).
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static object Deserialize(XmlPersistArgs parameters)
        {
            return XmlPersistor.Internal.XmlPersistor.Deserialize(parameters);
        }
        /// <summary>
        /// Vytvoří objekt ze serializovaného stavu, který je dodán jako string do této metody.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static T Deserialize<T>(string source)
        {
            return Deserialize<T>(CreateArgs(source));
        }
        /// <summary>
        /// Vytvoří objekt ze serializovaného stavu, který je definován v argumentu (může to být string, nebo soubor).
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static T Deserialize<T>(XmlPersistArgs parameters)
        {
            return XmlPersistor.Internal.XmlPersistor.Deserialize<T>(parameters);
        }
        /// <summary>
        /// Určená data rekonstruuje a naplní je do předaného objektu.
        /// Pokud objekt je null, vytvoří jej.
        /// </summary>
        /// <param name="source">Jméno nebo obsah XML souboru (provede se autodetekce)</param>
        /// <param name="data">Cílový objekt, do něhož se data z XML vkládají</param>
        public static void LoadTo(string source, object data)
        {
            LoadTo(CreateArgs(source), data);
        }
        /// <summary>
        /// Určená data rekonstruuje a naplní je do předaného objektu.
        /// Předaný objekt nemůže být null, protože se nepředává jako reference (ref).
		/// Pokud by měl být objekt null, je třeba využít metodu Persist.Deserialize().
        /// </summary>
        /// <param name="parameters">Vstupní data a parametry</param>
        /// <param name="data">Cílový objekt, do něhož se data z XML vkládají</param>
        public static void LoadTo(XmlPersistArgs parameters, object data)
        {
            XmlPersistor.Internal.XmlPersistor.LoadTo(parameters, data);
        }
        /// <summary>
        /// Hodnoty ze vstupního objektu přenese do cílového objektu.
        /// Používá XML persistenci, takže přenáší jen ty hodnoty, které jsou serializovatelné.
        /// Provádí tedy hluboké klonování.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        public static void CloneTo(object source, object target)
        {
            if (source == null || target == null) return;

            XmlPersistArgs args = XmlPersistArgs.MinimalXml;
            string xmlSource = XmlPersistor.Internal.XmlPersistor.Serialize(source, args);
            LoadTo(xmlSource, target);
        }
        /// <summary>
        /// Vrátí defaultní parametry, do nichž naplní source do XmlContent nebo do XmlFile
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private static XmlPersistArgs CreateArgs(string source)
        {
            if (source == null) return null;
            XmlPersistArgs parameters = XmlPersistArgs.Default;
            if (source.Trim().StartsWith("<"))
                parameters.XmlContent = source;
            else
                parameters.XmlFile = source;
            return parameters;
        }
        #endregion
    }
    #endregion
    #region class PersistArgs : parametry pro persistenci objektu
    /// <summary>
    /// class PersistArgs : parametry pro persistenci objektu
    /// </summary>
    public class XmlPersistArgs
    {
        /// <summary>
        /// Konstruktor
        /// </summary>
        public XmlPersistArgs()
        {
            XmlWriterSettings xs = new XmlWriterSettings();
            xs.ConformanceLevel = ConformanceLevel.Document;
            xs.Encoding = Encoding.UTF8;
            xs.CheckCharacters = false;
            xs.Indent = true;
            xs.IndentChars = "  ";
            xs.NewLineHandling = NewLineHandling.Entitize;
            xs.NewLineChars = Environment.NewLine;
            xs.NewLineOnAttributes = false;
            xs.OmitXmlDeclaration = false;
            this.WriterSettings = xs;
        }
        /// <summary>
        /// Defaultní parametry
        /// </summary>
        public static XmlPersistArgs Default
        {
            get { return new XmlPersistArgs(); }
        }
        /// <summary>
        /// Parametry pro vytváření minimálního XML textu
        /// </summary>
        public static XmlPersistArgs MinimalXml
        {
            get
            {
                XmlPersistArgs args = new XmlPersistArgs();
                args.WriterSettings.ConformanceLevel = ConformanceLevel.Document;
                args.WriterSettings.Encoding = Encoding.UTF8;
                args.WriterSettings.CheckCharacters = false;
                args.WriterSettings.Indent = false;
                args.WriterSettings.IndentChars = "";
                args.WriterSettings.NewLineHandling = NewLineHandling.None;
                args.WriterSettings.NewLineChars = Environment.NewLine;
                args.WriterSettings.NewLineOnAttributes = false;
                args.WriterSettings.OmitXmlDeclaration = false;
                return args;
            }
        }
        /// <summary>
        /// Nastavení pro zápis XML
        /// </summary>
        public XmlWriterSettings WriterSettings { get; set; }
        /// <summary>
        /// Soubor pro načtení/uložení XML. Pokud bude null, nebude se načítat/ukládat ze souboru, ale použije se string XmlContent.
        /// </summary>
        public string XmlFile { get; set; }
        /// <summary>
        /// Obsah XML dat.
        /// Při načítání (Load), pokud je určen soubor XmlFile, je obsah uložen sem (obsah souboru se načte a vloží do XmlContent). 
        /// Pokud při Load není soubor XmlFile určen, přebírá se XML text odsud.
        /// Při ukládání (Save) je obsah XML vždy uložen i sem.
        /// </summary>
        public string XmlContent { get; set; }
        /// <summary>
        /// Stav deserializace = obsahuje případné problémy
        /// </summary>
        public XmlDeserializeStatus DeserializeStatus { get; set; }
    }
    /// <summary>
    /// Stav procesu deserializace
    /// </summary>
    public enum XmlDeserializeStatus
    {
        /// <summary>Ještě nezačal</summary>
        None,
        /// <summary>Právě probíhá</summary>
        Processing,
        /// <summary>Není vstup</summary>
        NotInput,
        /// <summary>Chybný formát</summary>
        BadFormatPersistent,
        /// <summary>Chybná data</summary>
        BadFormatData,
        /// <summary>Chybná hodnota</summary>
        BadFormatValue
    }
    #endregion
}
